﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json.Nodes;

namespace DotNetCommon.Extensions
{
    /// <summary>
    /// JsonObject、JsonArray 扩展类
    /// </summary>
    public static class JsonExtensions
    {
        #region JsonArray ContainsObject/ContainsObjectAny/ContainsObjectAll/
        /// <summary>
        /// 当前集合(<c>jsonArray</c>)是否含有<c>value</c>
        /// <list type="bullet">
        /// <item>当<c>jsonArray</c>为空时,直接返回false,否则下一步;</item>
        /// <item>返回<c>jsonArray</c>是否含有<c>value</c>;</item>
        /// </list>
        /// 示例:
        /// <code>
        /// new[] { 1, 2, 3 }.ToJsonArray().ContainsObject(1).ShouldBe(true);
        /// </code>
        /// </summary>
        /// <remarks>比较前会将<c>JsonArray</c>反序列化为List&lt;T></remarks>
        public static bool ContainsObject<T>(this JsonArray jsonArray, T value)
            => ContainsObject(jsonArray, value, null);

        /// <summary>
        /// 当前集合(<c>jsonArray</c>)是否含有<c>value</c>
        /// <list type="bullet">
        /// <item>当<c>jsonArray</c>为空时,直接返回false,否则下一步;</item>
        /// <item>返回<c>jsonArray</c>是否含有<c>value</c>;</item>
        /// </list>
        /// 示例:
        /// <code>
        /// new[] { 1, 2, 3 }.ToJsonArray().ContainsObject(1).ShouldBe(true);
        /// </code>
        /// </summary>
        /// <remarks>比较前会将<c>JsonArray</c>反序列化为List&lt;T></remarks>
        public static bool ContainsObject<T>(this JsonArray jsonArray, T value, IEqualityComparer<T> equalityComparer = null)
        {
            if (jsonArray == null || jsonArray.Count == 0) return false;
            var seq = jsonArray.ToJsonString().ToObject<List<T>>();
            return seq.Contains(value, equalityComparer);
        }

        /// <summary>
        /// 当前集合(<c>jsonArray</c>)是否含有<c>values</c>中的任何一个
        /// <list type="bullet">
        /// <item>当<c>objects</c>为空时,直接返回true,否则下一步;</item>
        /// <item>当<c>jsonArray</c>为空时,直接返回false,否则下一步;</item>
        /// <item>返回<c>jsonArray</c>和<c>objects</c>是否有交叉(Intersect);</item>
        /// </list>
        /// 示例:
        /// <code>
        /// new[] { 1, 2, 3 }.ToJsonArray().ContainsObjectAny(new[] { 1, 5 }).ShouldBe(true);
        /// </code>
        /// </summary>
        /// <remarks>比较前会将<c>JsonArray</c>反序列化为List&lt;T></remarks>
        public static bool ContainsObjectAny<T>(this JsonArray jsonArray, IEnumerable<T> objects)
            => ContainsObjectAny<T>(jsonArray, objects, null);

        /// <summary>
        /// 当前集合(<c>jsonArray</c>)是否含有<c>objects</c>中的任何一个
        /// <list type="bullet">
        /// <item>当<c>objects</c>为空时,直接返回true,否则下一步;</item>
        /// <item>当<c>jsonArray</c>为空时,直接返回false,否则下一步;</item>
        /// <item>返回<c>jsonArray</c>和<c>objects</c>是否有交叉(Intersect);</item>
        /// </list>
        /// 示例:
        /// <code>
        /// new[] { 1, 2, 3 }.ToJsonArray().ContainsObjectAny(new[] { 1, 5 }).ShouldBe(true);
        /// </code>
        /// </summary>
        /// <remarks>比较前会将<c>JsonArray</c>反序列化为List&lt;T></remarks>
        public static bool ContainsObjectAny<T>(this JsonArray jsonArray, IEnumerable<T> objects, IEqualityComparer<T> equalityComparer = null)
        {
            if (objects.IsNullOrEmpty()) return true;
            if (jsonArray == null || jsonArray.Count == 0) return false;
            var seq = jsonArray.ToJsonString().ToObject<List<T>>();
            return seq.ContainsAny(objects, equalityComparer);
        }

        /// <summary>
        /// 当前集合(<c>jsonArray</c>)是否包含<c>objects</c>中的全部
        /// <list type="bullet">
        /// <item>当<c>objects</c>为空时,直接返回true,否则下一步;</item>
        /// <item>当<c>jsonArray</c>为空时,直接返回false,否则下一步;</item>
        /// <item>返回<c>objects</c>减去<c>jsonArray</c>后是否为空(Except);</item>
        /// </list>
        /// 示例:
        /// <code>
        /// new[] { 1, 2, 3 }.ToJsonArray().ContainsObjectAll(new[] { 1, 2 }).ShouldBe(true);
        /// </code>
        /// </summary>
        /// <remarks>比较前会将<c>JsonArray</c>反序列化为List&lt;T></remarks>
        public static bool ContainsObjectAll<T>(this JsonArray jsonArray, IEnumerable<T> objects)
            => ContainsObjectAll<T>(jsonArray, objects, null);

        /// <summary>
        /// 当前集合(<c>jsonArray</c>)是否包含<c>objects</c>中的全部
        /// <list type="bullet">
        /// <item>当<c>objects</c>为空时,直接返回true,否则下一步;</item>
        /// <item>当<c>jsonArray</c>为空时,直接返回false,否则下一步;</item>
        /// <item>返回<c>objects</c>减去<c>jsonArray</c>后是否为空(Except);</item>
        /// </list>
        /// 示例:
        /// <code>
        /// new[] { 1, 2, 3 }.ToJsonArray().ContainsObjectAll(new[] { 1, 2 }).ShouldBe(true);
        /// </code>
        /// </summary>
        /// <remarks>比较前会将<c>JsonArray</c>反序列化为List&lt;T></remarks>
        public static bool ContainsObjectAll<T>(this JsonArray jsonArray, IEnumerable<T> objects, IEqualityComparer<T> equalityComparer = null)
        {
            if (objects.IsNullOrEmpty()) return true;
            if (jsonArray == null || jsonArray.Count == 0) return false;
            var seq = jsonArray.ToJsonString().ToObject<List<T>>();
            return seq.ContainsAll(objects, equalityComparer);
        }
        #endregion

        #region JsonArray AddFluent/AddRangeFluent/ClearFluent/InsertAtFluent/RemoveAtFluent/RemoveFluent/SetFluent
        /// <summary>
        /// 向集合<c>jsonArray</c>中添加项<c>item</c>并返回自身
        /// </summary>
        public static JsonArray AddFluent(this JsonArray jsonArray, JsonNode item)
        {
            jsonArray.Add(item);
            return jsonArray;
        }

        /// <summary>
        /// 向集合<c>jsonArray</c>中添加项集合<c>items</c>并返回自身
        /// </summary>
        public static JsonArray AddRangeFluent<T>(this JsonArray jsonArray, IEnumerable<T> items)
        {
            if (items.IsNullOrEmpty()) return jsonArray;
            foreach (var item in items) jsonArray.Add(item);
            return jsonArray;
        }

        /// <summary>
        /// 清空集合<c>jsonArray</c>并返回自身
        /// </summary>
        public static JsonArray ClearFluent(this JsonArray jsonArray)
        {
            jsonArray.Clear();
            return jsonArray;
        }

        /// <summary>
        /// 向集合<c>jsonArray</c>中指定位置插入向<c>item</c>并返回自身
        /// </summary>
        public static JsonArray InsertAtFluent(this JsonArray jsonArray, int index, JsonNode item)
        {
            jsonArray.Insert(index, item);
            return jsonArray;
        }

        /// <summary>
        /// 从集合<c>jsonArray</c>中移除指定位置的项,并返回自身
        /// </summary>
        public static JsonArray RemoveAtFluent(this JsonArray jsonArray, int index)
        {
            jsonArray.RemoveAt(index);
            return jsonArray;
        }

        /// <summary>
        /// 从集合<c>jsonArray</c>中移除符合条件的项,并返回自身
        /// </summary>
        /// <remarks>
        /// 注意:
        /// <list type="bullet">
        /// <item>如果集合为null,抛出异常</item>
        /// </list>
        /// </remarks>
        public static JsonArray RemoveFluent(this JsonArray jsonArray, Predicate<JsonNode> match)
        {
            Ensure.NotNull(jsonArray, nameof(jsonArray));
            Ensure.NotNull(match, nameof(match));
            for (var i = 0; i < jsonArray.Count; i++)
            {
                if (match(jsonArray[i]))
                {
                    jsonArray.RemoveAt(i);
                    i--;
                }
            }
            return jsonArray;
        }

        /// <summary>
        /// Fluent风格: 设置集合中指定索引的值
        /// </summary>
        /// <remarks>
        /// 注意:
        /// <list type="bullet">
        /// <item>如果集合为null或索引超出,抛出异常</item>
        /// </list>
        /// </remarks>
        public static JsonArray SetFluent(this JsonArray jsonArray, int index, JsonNode b)
        {
            jsonArray[index] = b;
            return jsonArray;
        }

        /// <summary>
        /// Fluent风格: 设置集合中指定索引的值
        /// </summary>
        /// <remarks>
        /// 注意:
        /// <list type="bullet">
        /// <item>如果集合为null或索引超出,抛出异常</item>
        /// </list>
        /// </remarks>
        public static JsonArray SetFluent(this JsonArray jsonArray, int index, Func<JsonNode, JsonNode> func)
        {
            jsonArray[index] = func(jsonArray[index]);
            return jsonArray;
        }

        /// <summary>
        /// Fluent风格: 批量设置集合中的值
        /// </summary>
        /// <remarks>
        /// 注意:
        /// <list type="bullet">
        /// <item>如果集合为null或索引超出,抛出异常</item>
        /// </list>
        /// </remarks>
        public static JsonArray SetFluent(this JsonArray jsonArray, Func<JsonNode, bool> filter, Func<JsonNode, JsonNode> func)
        {
            for (int i = 0; i < jsonArray.Count; i++)
            {
                var b = filter?.Invoke(jsonArray[i]);
                if (b == false) continue;
                jsonArray[i] = func(jsonArray[i]);
            }
            return jsonArray;
        }
        #endregion

        #region JsonObject SetFluent/SetBatchFluent/RemoveFluent/ClearFluent
        /// <summary>
        /// 给<c>jsonObject</c>设置属性值, 并返回自身
        /// </summary>
        public static JsonObject SetFluent(this JsonObject jsonObject, string key, JsonNode value)
        {
            jsonObject[key] = value;
            return jsonObject;
        }

        /// <summary>
        /// 给<c>jsonObject</c>设置属性值, 并返回自身
        /// </summary>
        public static JsonObject SetFluent(this JsonObject jsonObject, string key, Func<JsonNode, JsonNode> func)
        {
            jsonObject[key] = func(jsonObject[key]);
            return jsonObject;
        }

        /// <summary>
        /// 移除<c>jsonObject</c>中的某个属性
        /// </summary>
        public static JsonObject RemoveFluent(this JsonObject jsonObject, string key)
        {
            jsonObject.Remove(key);
            return jsonObject;
        }

        /// <summary>
        /// 清空<c>jsonObject</c>中的属性
        /// </summary>
        public static JsonObject ClearFluent(this JsonObject jsonObject)
        {
            jsonObject.Clear();
            return jsonObject;
        }
        #endregion

        #region JsonArray FindIndex/FindLastIndex
        /// <summary>
        /// 类似 List.FindIndex()
        /// </summary>
        /// <remarks>
        /// 注意:
        /// <list type="bullet">
        /// <item>如果集合为null或索引超出,抛出异常</item>
        /// </list>
        /// </remarks>
        public static int FindIndex(this JsonArray jsonArray, Predicate<JsonNode> match)
        {
            for (int i = 0; i < jsonArray.Count; i++)
            {
                if (match(jsonArray[i])) return i;
            }
            return -1;
        }

        /// <summary>
        /// 类似 List.FindLastIndex()
        /// </summary>
        /// <remarks>
        /// 注意:
        /// <list type="bullet">
        /// <item>如果集合为null或索引超出,抛出异常</item>
        /// </list>
        /// </remarks>
        public static int FindLastIndex(this JsonArray jsonArray, Predicate<JsonNode> match)
        {
            for (int i = jsonArray.Count - 1; i >= 0; i--)
            {
                if (match(jsonArray[i])) return i;
            }
            return -1;
        }
        #endregion
    }
}
